package com.deliccio.connect;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;

import org.apache.log4j.Logger;

public class DAO<T extends Entidad> implements IDAO<T>{

	private static Logger log = Logger.getLogger(DAO.class);
	
	private Class<Entidad> clazz;

	protected String sqlQuery=null;

	protected Query q=null;
	protected EntityManager em;

	private EntityManagerFactory emf;

	@SuppressWarnings("unchecked")
	public DAO(){
		clazz=(Class<Entidad>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		log.info("Crea aspecto de la Entidad:"+clazz.getName());
	}
	
	@PersistenceUnit
	public void setEntityManagerFactory(EntityManagerFactory emf){
		log.info("Asignacion del EntityManagerFactory:"+clazz.getName() + " emf: "+emf.toString());
		this.emf=emf;
	}

	@PersistenceContext
	public void setEm(EntityManager em){
		log.info("Asignacion del EntityManager:"+clazz.getName() + " em: "+em.toString());
		this.em=em;
	}
	
	@SuppressWarnings("unchecked")
	public T get(Integer id){
		try{
			log.info(" Entro al metodo get de Entidad "+clazz.getName()+" con id:"+id);			
			return (T) em.find(clazz,id);
		}
		catch(Exception e){
			return null;
		}
	}

	@SuppressWarnings({"unchecked","cast"})
	public List<T> getTodos(){
		Entity e=(Entity) clazz.getAnnotation(Entity.class);
		String nombre=null;
		if(e == null || e.name() == null || e.name().length() == 0)
			nombre=clazz.getSimpleName();
		else
			nombre=e.name();
		String sql="SELECT e FROM " + nombre + " e";
		log.info(" Entro al metodo getTodos de Entidad "+clazz.getName() + "  con query: "+sql);
		return em.createQuery(sql).getResultList();
	}

	public void guardar(T objeto){
		EntityManager emReg=emf.createEntityManager();
		try{
			log.warn(" Entro al metodo guardar de Entidad "+clazz.getName());
			emReg.getTransaction().begin();
			log.warn(" Transaction abierta  "+clazz.getName() + " con id :"+objeto.getId());
			
			if(objeto.getId() != null)
				emReg.merge(objeto);
			else
				emReg.persist(objeto);
			
			log.warn(" Transaction terminada  "+clazz.getName() + " con id :"+objeto.getId());
			emReg.getTransaction().commit();
			log.warn(" Transaction commint  "+clazz.getName());
		}
		catch(Exception e){
			System.err.println("Error:" + e.getMessage());
			log.error(" Transaction rollback  "+clazz.getName()+" error: "  + e.getMessage());
			e.printStackTrace();
			em.getTransaction().rollback();
		}
		finally{
			if(emReg != null)
				emReg.close();
			log.warn(" Transaction cerrada  "+clazz.getName());
		}

	}

	@Override
	public void eliminar(T objeto){
		EntityManager emReg=emf.createEntityManager();
		
		try{
			log.warn(" Entro al metodo eliminar de Entidad "+clazz.getName());
		//	emReg.getTransaction().begin();
			log.warn(" Transaction abierta  "+clazz.getName() + " con id :"+objeto.getId());
		//	emReg.refresh(objeto);
		//	objeto = (T) emReg.find(objeto.getClass(),objeto.getId());
			if(objeto.getId() != null)
				emReg.remove(objeto);
			
			log.warn(" Transaction terminada  "+clazz.getName() + " con id :"+objeto.getId());
			//	emReg.getTransaction().commit();
			log.warn(" Transaction commint  "+clazz.getName());
		}
		catch(Exception e){
			System.err.println("Error:" + e.getMessage());
			log.error(" Transaction rollback  "+clazz.getName()+" error: "  + e.getMessage());
			e.printStackTrace();
			//	em.getTransaction().rollback();
		}
		finally{
			if(emReg != null)
				//	emReg.close();
			log.warn(" Transaction cerrada  "+clazz.getName());
		}
		
	}

}
